import CONFIG from './config.js'
import MapCell from './map_cell.js'
import Weapon from './weapon.js'

class GameMap {
    constructor(game) {
        this.map_vector = [];
        this.game = game;

        this.map_size = CONFIG.map_size;
        this.init_map();
        this.init_map_info();

    }

    static clone_map(game, row, col, role) {
        let test_map = new GameMap(game);
        let game_map_vector = game.map.map_vector;
        test_map.map_vector.forEach(function (cell, index) {
            cell.reset_cell(game_map_vector[index].role);
        });
        if (row !== undefined) {
            let sel_cell = test_map.row_col_2_vector(row, col);
            sel_cell.role = role;
        }

        test_map.calc_path();

        return test_map;
    }

    static allow_create_weapon(game, row, col) {
        let test_map = GameMap.clone_map(game, row, col, 2);
        return !!test_map.start_cell.last_map_cell
    }

    static check_cell_in_path(game, row, col, role) {
        let test_map = GameMap.clone_map(game, row, col, role || 1);
        let sel_cell = test_map.row_col_2_vector(row, col);
        return test_map.is_in_path(sel_cell)
    }

    init_map() {
        if (!this.map_vector.length) {
            for (let row = 0; row < this.map_size; row++) {
                for (let col = 0; col < this.map_size; col++) {
                    let map_cell = new MapCell(this, row, col, 1);
                    this.map_vector.push(map_cell);
                }
            }
        } else {
            this.map_vector.forEach(function (cell) {
                cell.reset_cell();
            });
        }
        this.start_cell = this.map_vector[0];
        this.end_cell = this.map_vector[this.map_vector.length - 1];
    }

    init_map_info() {
        let canvas_map = document.getElementById(CONFIG.canvas_map_id);
        let ctx_map = canvas_map.getContext("2d");

        let width = canvas_map.width;
        let height = canvas_map.height;
        let cell_width = width / this.map_size;
        let cell_height = height / this.map_size;
        let scale = width / canvas_map.clientWidth;

        this.map_info = {
            ctx_map: ctx_map,
            width: width,
            height: height,
            cell_width: cell_width,
            cell_height: cell_height,
            scale: scale
        };
    };

    row_col_2_vector(row, col) {
        if (arguments.length === 1) {
            col = row[1];
            row = row[0];
        }
        let index = (row * this.map_size) + col;
        return this.map_vector[index];
    };

    is_in_path(map_cell) {
        if (!map_cell) return false;

        let next_cell = this.start_cell.last_map_cell;

        while (next_cell) {
            if (map_cell.row === next_cell.row && map_cell.col === next_cell.col) {
                return true;
            }
            next_cell = next_cell.last_map_cell;
        }
        return false;
    };

    xy_2_vector(x, y) {
        if (arguments.length === 1) {
            y = x[1];
            x = x[0];
        }
        let col = (x / this.map_info.cell_width) | 0;
        let row = (y / this.map_info.cell_height) | 0;
        return this.row_col_2_vector(row, col);
    };

    calc_path(target_map_cell) {
        let map_len = this.map_vector.length;
        let pending_arr = [];
        for (let i = 0; i < map_len; i++) {
            let map_cell = this.map_vector[i];
            map_cell.distance = Infinity;
            map_cell.last_map_cell = null;
            if (map_cell.role === 1) {
                pending_arr.push(map_cell);
            }
        }

        let start_map_cell = this.end_cell;
        if (target_map_cell) {
            start_map_cell = this.row_col_2_vector(target_map_cell);
        }
        start_map_cell.distance = 0;

        while (pending_arr.length) {
            let min_map_cell = null;

            if (pending_arr.length >= 2) {
                pending_arr.sort(function (a, b) {
                    return a.distance - b.distance;
                });
                if (this.game.config.spirit.random_path) {
                    let mc0 = pending_arr[0], mc2 = pending_arr[1];
                    if (mc0.distance === mc2.distance) {
                        let index = Math.round(Math.random());
                        min_map_cell = pending_arr.splice(index, 1)[0];
                    }
                }
            }
            !min_map_cell && (min_map_cell = pending_arr.shift());
            min_map_cell.find_mark_next();
        }
    };

    draw() {
        let map_info = this.map_info;
        let ctx = map_info.ctx_map;
        let {width, height} = map_info;

        if (!GameMap.image) GameMap.image = this.bg_draw();

        ctx.clearRect(0, 0, width, height);
        ctx.drawImage(GameMap.image, 0, 0);

        this.draw_start_end_mark();

        let level_mng = this.game.level_manager;
        if (level_mng && (level_mng.is_running || level_mng.is_finish)) {
            this.draw_path();
        }
    };

    draw_path() {
        let map_cell = this.start_cell.last_map_cell;
        this.path_frame_index = this.path_frame_index || 0;
        this.path_frame_index = (this.path_frame_index + 1) % 2;

        while (map_cell && map_cell.last_map_cell) {
            map_cell.draw_mark("path", this.path_frame_index);
            map_cell = map_cell.last_map_cell;
        }
    };

    draw_start_end_mark() {
        if (!GameMap.start_frames) {
            let weapon = new Weapon(this.game, 0, 0, {});
            GameMap.start_frames = [weapon.bg_draw(3),
                weapon.bg_draw(4), weapon.bg_draw(5)];

            GameMap.end_frames = [weapon.bg_draw(6),
                weapon.bg_draw(5)];
        }

        let map_info = this.map_info;
        let ctx = map_info.ctx_map;

        this.start_frame_index = this.start_frame_index || 0;
        let start_frame_len = GameMap.start_frames.length;
        this.start_frame_index = (this.start_frame_index + 1) % start_frame_len;

        this.end_frame_index = this.end_frame_index || 0;
        let end_frame_len = GameMap.end_frames.length;
        this.end_frame_index = (this.end_frame_index + 1) % end_frame_len;

        let map_cell = this.start_cell;
        let start_xy = map_cell.get_start_xy();
        let [x, y] = start_xy;
        ctx.drawImage(GameMap.start_frames[this.start_frame_index], x, y);

        map_cell = this.end_cell;
        start_xy = map_cell.get_start_xy();
        [x, y] = start_xy;
        ctx.drawImage(GameMap.end_frames[this.end_frame_index], x, y);
    };

    bg_draw() {
        let map_info = this.map_info;
        let {width, height} = map_info;
        let {cell_width, cell_height} = map_info;

        let bg_ele = document.createElement("canvas");
        let ctx = bg_ele.getContext("2d");

        bg_ele.width = width;
        bg_ele.height = height;

        ctx.strokeStyle = "#aaa";
        ctx.lineWidth = 1;

        for (let row = 0; row < this.map_size; row++) {
            ctx.moveTo(0, cell_height * row);
            ctx.lineTo(width, cell_height * row);
        }
        for (let col = 0; col < this.map_size; col++) {
            ctx.moveTo(cell_width * col, 0);
            ctx.lineTo(cell_width * col, height);
        }
        ctx.stroke();

        return bg_ele;
    };
}

export default GameMap;